/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.meta.rpc.dictionary;

import com.alibaba.fastjson2.JSONObject;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.je.common.base.DynaBean;
import com.je.common.base.JsonBuilder;
import com.je.common.base.constants.dd.DDType;
import com.je.common.base.constants.tree.NodeType;
import com.je.common.base.entity.QueryInfo;
import com.je.common.base.mapper.query.Query;
import com.je.common.base.service.MetaService;
import com.je.common.base.util.SecurityUserHolder;
import com.je.common.base.util.StringUtil;
import com.je.core.entity.extjs.JSONTreeNode;
import com.je.ibatis.extension.conditions.ConditionsWrapper;
import com.je.meta.cache.dd.DicCache;
import com.je.meta.cache.dd.DicInfoCache;
import com.je.meta.cache.dd.DicQuickCache;
import com.je.meta.model.dd.DictionaryItemVo;
import com.je.meta.service.common.MetaBeanService;
import org.apache.commons.lang.StringUtils;
import org.apache.servicecomb.provider.pojo.RpcSchema;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RpcSchema(schemaId = "dictionaryRpcService")
public class DictionaryRpcServiceImpl implements DictionaryRpcService {

    private static final Logger logger = LoggerFactory.getLogger(DictionaryRpcServiceImpl.class);

    @Autowired
    private MetaService metaService;
    @Autowired
    private MetaBeanService metaBeanService;
    @Autowired
    private DicCache dicCache;
    @Autowired
    private DicQuickCache dicQuickCache;
    @Autowired
    private DicInfoCache dicInfoCache;
    @Autowired
    private DictionaryItemRpcService dictionaryItemRpcService;



    public List<DynaBean> getAllDicItems(String ddCode){
        DynaBean dictionary = metaService.selectOne("JE_CORE_DICTIONARY", ConditionsWrapper.builder().eq("DICTIONARY_DDCODE",ddCode).apply("and (SY_STATUS = '' or SY_STATUS = '1')"));
        if(dictionary == null){
            return null;
        }
        //查询字典项
        List<DynaBean> items = metaService.select("JE_CORE_DICTIONARYITEM", ConditionsWrapper.builder()
                .eq("SY_FLAG", "1")
                .ne("SY_NODETYPE", "ROOT")
                .eq("DICTIONARYITEM_DICTIONARY_ID", dictionary.getStr("JE_CORE_DICTIONARY_ID")));
        return items;
    }


    @Override
    public JSONObject getAllListDicItem() {
        return getAllListDicItemWithWhere(null);
    }

    /**
     * 获取指定列表字典的字典项
     *
     * @param whereSql 查询sql
     * @return
     */
    @Override
    public JSONObject getAllListDicItemWithWhere(String whereSql, Object... params) {
        JSONObject returnObj = new JSONObject();
        ConditionsWrapper wrapper = ConditionsWrapper.builder().eq("DICTIONARY_DDTYPE", DDType.LIST).apply("and (SY_STATUS = '' or SY_STATUS = '1')");
        if (!Strings.isNullOrEmpty(whereSql)) {
            wrapper.apply(whereSql, params);
        }
        List<DynaBean> dictionarys = metaService.select("JE_CORE_DICTIONARY", wrapper);
        for (DynaBean dictionary : dictionarys) {
            String ddCode = dictionary.getStr("DICTIONARY_DDCODE");
            List<DictionaryItemVo> voList = buildChildrenList(dictionary, false, new Query(), "");
            returnObj.put(ddCode, voList);
        }
        return returnObj;
    }

    /**
     * 为voList封装视图对象
     *
     * @param dic
     * @param en
     * @param query
     * @param itemCode
     */
    @Override
    public List<DictionaryItemVo> buildChildrenList(DynaBean dic, Boolean en, Query query, String itemCode) {
        ConditionsWrapper wrapper = ConditionsWrapper.builder()
                .eq("SY_FLAG", "1")
                .ne("SY_NODETYPE", "ROOT")
                .eq("DICTIONARYITEM_DICTIONARY_ID", dic.getStr("JE_CORE_DICTIONARY_ID"))
                //指定字典项
                .eq(StringUtil.isNotEmpty(itemCode), "DICTIONARYITEM_ITEMCODE", itemCode);
        //添加where条件
        query.buildWrapper(wrapper);

        //添加order条件
        String orderSql = query.buildOrder();
        if (StringUtils.isNotEmpty(orderSql)) {
            wrapper.apply(" ORDER BY ").apply(orderSql);
        } else {
            wrapper.apply(" ORDER BY SY_ORDERINDEX");
        }

        //查询字典项
        List<DynaBean> items = metaService.select("JE_CORE_DICTIONARYITEM", wrapper);
        List<DictionaryItemVo> voList = new ArrayList<>();
        for (int i = 0; i < items.size(); i++) {
            DynaBean item = items.get(i);
            DictionaryItemVo vo = new DictionaryItemVo();
            vo.setId(item.getStr("JE_CORE_DICTIONARYITEM_ID"));
            //国际化
            if (en) {
                vo.setText(item.getStr("DICTIONARYITEM_ITEMNAME_EN"));
            }
            vo.setCode(item.getStr("DICTIONARYITEM_ITEMCODE"));
            vo.setIcon(item.getStr("DICTIONARYITEM_ICON"));
            vo.setText(item.getStr("DICTIONARYITEM_ITEMNAME"));
            vo.setTextColor(item.getStr("DICTIONARYITEM_FONTCOLOR"));
            vo.setIconCls(item.getStr("DICTIONARYITEM_ICON"));
            vo.setBackgroundColor(item.getStr("DICTIONARYITEM_BACKGROUNDCOLOR"));
            voList.add(vo);
        }
        return voList;
    }

    /**
     * 缓存所有列表字典
     */
    @Override
    public void doCacheAllListTypeDicItem() {
        //缓存所有列表类型的字典
        List<DynaBean> dictionarys = metaService.select("JE_CORE_DICTIONARY", ConditionsWrapper.builder().eq("DICTIONARY_DDTYPE", DDType.LIST)
                        .apply("and (SY_STATUS = '' or SY_STATUS = '1')"),
                "JE_CORE_DICTIONARY_ID,DICTIONARY_DDCODE,DICTIONARY_ITEMROOT_ID,DICTIONARY_WHERESQL,DICTIONARY_WHERESQL");
        logger.info("Ready to cache dictionary size {}", dictionarys.size());

        Map<String, String> dicMap = Maps.newHashMap();
        Map<String, List<JSONTreeNode>> dicQuickMap = Maps.newHashMap();

        int partSize = 300;
        List<List<DynaBean>> partList = Lists.partition(dictionarys, partSize);
        logger.info("Cache part size is {} and parted size is {}. next begin to cache parts...", partSize, partList.size());
        partList.parallelStream().forEach(eachDictionaryList -> {
            buildDicCache(eachDictionaryList, dicMap, dicQuickMap);
        });

        //写入缓存
        String currentTenantId = SecurityUserHolder.getCurrentAccountTenantId();
        if (Strings.isNullOrEmpty(currentTenantId)) {
            dicCache.putMapCache(dicMap);
            dicQuickCache.putMapCache(dicQuickMap);
        } else {
            dicCache.putMapCache(currentTenantId, dicMap);
            dicQuickCache.putMapCache(currentTenantId, dicQuickMap);
        }

        logger.info("Cached dic size {}.", dicMap.size());
        logger.info("Cached dic quick size {}.", dicQuickMap.size());
        //由于内容较多，此处移除内容，避免垃圾回收没有回收前的内存占用问题
        dicMap.clear();
        dicQuickMap.clear();
    }

    private void buildDicCache(List<DynaBean> dictionarys, Map<String, String> dicMap, Map<String, List<JSONTreeNode>> dicQuickMap) {
        List<String> dictionaryIds = new ArrayList<>(dictionarys.size());
        dictionarys.forEach(eachBean -> {
            dictionaryIds.add(eachBean.getStr("JE_CORE_DICTIONARY_ID"));
        });

        ConditionsWrapper itemQueryWrapper = ConditionsWrapper.builder().in("DICTIONARYITEM_DICTIONARY_ID", dictionaryIds).and(conditionsWrapper -> {
            conditionsWrapper.eq("SY_FLAG", "1").or().eq("SY_NODETYPE", "ROOT");
        }).orderByAsc("SY_LAYER", "SY_ORDERINDEX");
        List<DynaBean> allItemList = metaService.select("JE_CORE_DICTIONARYITEM", itemQueryWrapper);

        for (DynaBean dictionary : dictionarys) {
            String ddCode = dictionary.getStr("DICTIONARY_DDCODE");
            List<DynaBean> items = new ArrayList<>();
            for (DynaBean eachItem : allItemList) {
                if (dictionary.getStr("JE_CORE_DICTIONARY_ID").equals(eachItem.getStr("DICTIONARYITEM_DICTIONARY_ID"))) {
                    items.add(eachItem);
                }
            }

            List<DictionaryItemVo> voList = Lists.newArrayList();
            for (DynaBean item : items) {
                if (NodeType.ROOT.equalsIgnoreCase(item.getStr("SY_NODETYPE")) || !"1".equals(item.getStr("SY_FLAG"))) {
                    continue;
                }
                DictionaryItemVo vo = new DictionaryItemVo();
                vo.setId(item.getStr("JE_CORE_DICTIONARYITEM_ID"));
                vo.setCode(item.getStr("DICTIONARYITEM_ITEMCODE"));
                vo.setIcon(item.getStr("DICTIONARYITEM_ICON"));
                vo.setText(item.getStr("DICTIONARYITEM_ITEMNAME"));
                vo.setTextColor(item.getStr("DICTIONARYITEM_FONTCOLOR"));
                vo.setIconCls(item.getStr("DICTIONARYITEM_ICON"));
                vo.setBackgroundColor(item.getStr("DICTIONARYITEM_BACKGROUNDCOLOR"));
                voList.add(vo);
            }

            //构建字典
            String ddValueStr = JsonBuilder.getInstance().buildObjListToJson(new Long(voList.size()), voList, false);
            dicMap.put(ddCode, ddValueStr);

            //构建字典项
            List<JSONTreeNode> jsonTreeNodeList = new ArrayList<JSONTreeNode>();
            JSONTreeNode n;
            for (DynaBean item : items) {
                n = new JSONTreeNode();
                if (!"1".equals(item.getStr("SY_FLAG")) && !NodeType.ROOT.equalsIgnoreCase(item.getStr("SY_NODETYPE"))) {
                    continue;
                }
                n.setChecked(false);
                n.setChildren(new ArrayList<JSONTreeNode>());
                n.setCode(item.getStr("DICTIONARYITEM_ITEMCODE"));
                n.setDisabled("0");
                n.setIcon(item.getStr("DICTIONARYITEM_ICON"));
                n.setId(item.getStr("JE_CORE_DICTIONARYITEM_ID"));
                n.setLayer(item.getStr("SY_LAYER", "0"));
                if (NodeType.LEAF.equalsIgnoreCase(item.getStr("SY_NODETYPE"))) {
                    n.setLeaf(true);
                } else {
                    n.setLeaf(false);
                }
                n.setNodeInfo(item.getStr("DICTIONARYITEM_NODEINFO"));
                n.setNodeInfoType(item.getStr("DICTIONARYITEM_NODEINFOTYPE"));
                n.setNodePath(item.getStr("SY_PATH"));
                n.setNodeType(item.getStr("SY_NODETYPE"));
                n.setOrderIndex(item.getStr("SY_ORDERINDEX"));
                n.setParent(item.getStr("SY_PARENT"));
                n.setText(item.getStr("DICTIONARYITEM_ITEMNAME"));
                n.setTreeOrderIndex(item.getStr("SY_TREEORDERINDEX"));
                n.setBean(new HashMap());
                jsonTreeNodeList.add(n);
            }
            dicQuickMap.put(ddCode, jsonTreeNodeList);
        }
    }

    /**
     * 缓存所有字典信息
     */
    @Override
    public void doCacheAllDicInfo() {
        dicInfoCache.clear();
        List<DynaBean> dics = metaService.select("JE_CORE_DICTIONARY", ConditionsWrapper.builder().apply("and (SY_STATUS = '' or SY_STATUS = '1')"), "JE_CORE_DICTIONARY_ID," + metaBeanService.getProQueryFields("JE_CORE_DICTIONARY"));
        Map<String, DynaBean> dicMap = new HashMap<>();
        for (DynaBean dic : dics) {
            dicMap.put(dic.getStr("DICTIONARY_DDCODE"), dic);
        }
        dicInfoCache.putMapCache(dicMap);
    }

    @Override
    public void reCacheDicInfo(String dicCodes) {
        //如果没有指定字典编码，则重新缓存所有字典
        if (Strings.isNullOrEmpty(dicCodes)) {
            doCacheAllDicInfo();
            return;
        }
        //执行重新缓存，指定字典编码
        List<DynaBean> dics = metaService.select("JE_CORE_DICTIONARY", ConditionsWrapper.builder().in("DICTIONARY_DDCODE", Splitter.on(",").splitToList(dicCodes))
                        .apply("and (SY_STATUS = '' or SY_STATUS = '1')"),
                "JE_CORE_DICTIONARY_ID," + metaBeanService.getProQueryFields("JE_CORE_DICTIONARY"));
        Map<String, DynaBean> dicMap = new HashMap<>();
        for (DynaBean dic : dics) {
            dicMap.put(dic.getStr("DICTIONARY_DDCODE"), dic);
        }
        dicInfoCache.putMapCache(dicMap);
    }

    /**
     * 根据字典项Code获取字典Name值
     *
     * @param dicItems 字典项集合
     * @param itemCode 字典项编码
     * @return
     */
    @Override
    public String getItemNameByCode(List<DictionaryItemVo> dicItems, String itemCode) {
        for (DictionaryItemVo item : dicItems) {
            if (itemCode.equals(item.getCode())) {
                return item.getText();
            }
        }
        return "";
    }

    /**
     * 更新省市县的分类信息
     */
    @Override
    public void syncSsxDic() {
        DynaBean dictionary = metaService.selectOne("JE_CORE_DICTIONARY", ConditionsWrapper.builder().apply("DICTIONARY_DDCODE='JE_COMM_SSQX'")
                .apply("and (SY_STATUS = '' or SY_STATUS = '1')"));
        DynaBean rootDic = metaService.selectOne("JE_CORE_DICTIONARYITEM",
                ConditionsWrapper.builder().apply(" DICTIONARYITEM_DICTIONARY_ID={0} AND SY_NODETYPE='ROOT'", dictionary.getStr("JE_CORE_DICTIONARY_ID")));
        syncSsxDicItem(rootDic);
    }

    private void syncSsxDicItem(DynaBean rootDic) {
        List<DynaBean> dicItems = metaService.select("JE_CORE_DICTIONARYITEM",
                ConditionsWrapper.builder().eq("SY_PARENT", rootDic.getStr("JE_CORE_DICTIONARYITEM_ID")));
        for (DynaBean dicItem : dicItems) {
            String code = dicItem.getStr("DICTIONARYITEM_ITEMCODE");
            String sStr = code.substring(0, 2);
            String shiStr = code.substring(2, 4);
            String xStr = code.substring(4);
            if (Integer.parseInt(shiStr) == 0 && Integer.parseInt(xStr) == 0) {
                dicItem.set("DICTIONARYITEM_CLASSIFY", "1");
            } else if (Integer.parseInt(xStr) == 0) {
                dicItem.set("DICTIONARYITEM_CLASSIFY", "2");
            } else {
                dicItem.set("DICTIONARYITEM_CLASSIFY", "3");
            }
            metaService.update(dicItem);
            syncSsxDicItem(dicItem);
        }
    }

    @Override
    public List<DictionaryItemVo> getDicList(String ddCode, Query query, Boolean en) {
        DynaBean dictionary = metaService.selectOne("JE_CORE_DICTIONARY", ConditionsWrapper.builder()
                .eq("DICTIONARY_DDTYPE", DDType.LIST)
                .eq("DICTIONARY_DDCODE", ddCode)
                .apply("and (SY_STATUS = '' or SY_STATUS = '1')"));
        List<DictionaryItemVo> voList = buildChildrenList(dictionary, en, query, "");
        return voList;
    }

    @Override
    public List<JSONTreeNode> getAllTyepDdListItems(String ddCode, Map<String, String> params, QueryInfo queryInfo, Boolean en) {
        return dictionaryItemRpcService.getDdItems(ddCode, params, queryInfo, en);
    }

}
